package com.zhoug.common3.http;


import com.zhoug.common3.Logger;

import java.io.IOException;
import java.math.BigDecimal;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;

import androidx.annotation.NonNull;
import okhttp3.Connection;
import okhttp3.Headers;
import okhttp3.Interceptor;
import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.Protocol;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import okhttp3.ResponseBody;
import okio.Buffer;
import okio.BufferedSource;

/**
 * 网络请求日志拦截器
 *
 * @Author 35574
 * @Date 2021/4/2
 * @Description
 */
public class HttpLogInterceptor implements Interceptor {
    private static final String TAG = ">>>HttpLog";
    private static final boolean DEBUG = false;
    private volatile int level = Level.NONE;
    private static final String Content_Type = "Content-Type";
    private static final String Content_Length = "Content-Length";
    private static final Charset UTF8 = StandardCharsets.UTF_8;


    /**
     * 日志级别
     */
    public static class Level {
        /**
         * 不打印日志
         */
        public static final int NONE = 0;
        public static final int BASIC = 1;
        /**
         * 只打印header
         */
        public static final int HEADERS = 2;
        /**
         * 打印全部
         */
        public static final int BODY = 3;

    }

    @Override
    public Response intercept(Chain chain) throws IOException {
        if (level == Level.NONE) {
            return chain.proceed(chain.request());
        }

        Request request = chain.request();
        RequestBody requestBody = request.body();
        boolean isLogBody = level == Level.BODY;//是否需要打印body
        boolean isLogHeaders = isLogBody || level == Level.HEADERS;//是否需要打印header

        /***打印请求日志*/
        //打印请求url
        Connection connection = chain.connection();
        Protocol protocol = connection != null ? connection.protocol() : Protocol.HTTP_1_1;
        Logger.d(TAG, "--> " + request.method() + " " + request.url() + " " + protocol);
        //打印请求header
        if (isLogHeaders) {
            logContentTypeAndLength(requestBody);
            logHeaders(request.headers(), true);
        }
        //打印请求body
        if (isLogBody && requestBody != null) {
            logStart("BODY");
            if (requestBody instanceof MultipartBody) {
//                Logger.d(TAG, "MultipartBody");
                //表单
                MultipartBody multipartBody = (MultipartBody) requestBody;
                String boundary = multipartBody.boundary();
                List<MultipartBody.Part> parts = multipartBody.parts();
                if (parts != null && parts.size() > 0) {
                    for (int i = 0; i < parts.size(); i++) {
                        Logger.d(TAG, "--" + boundary);
                        MultipartBody.Part part = parts.get(i);
                        logHeaders(part.headers(), false);
                        RequestBody partBody = part.body();
                        logContentTypeAndLength(partBody);
                        logBody(partBody);
                    }
                }
            } else {
                logBody(requestBody);
            }
            logEnd("BODY");
        }
        Logger.d(TAG, "--> END " + request.method());

        /***打印服务器返回日志*/
        long startTimes = System.nanoTime();
        Response response;
        try {
            response = chain.proceed(request);
        } catch (Exception e) {
            Logger.d(TAG, "<-- HTTP FAILED: " + e);
            throw e;
        }
        long tookMs = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startTimes);
        if (response != null) {
            request = response.request();
            int code = response.code();
            Logger.d(TAG, "<-- " + code + " " + response.message() + " " + request.url() + " (" + tookMs + ")");
            //打印header
            if (isLogHeaders) {
                logHeaders(response.headers(), true);
            }
            //打印body
            ResponseBody responseBody = response.body();
            if (isLogBody && responseBody != null) {
                logStart("BODY");
                MediaType contentType = responseBody.contentType();
                Charset charset = null;
                String type = "";
                if (contentType != null) {
                    charset = contentType.charset(UTF8);
                    type = contentType.toString();
                }
                if (charset == null) {
                    charset = UTF8;
                }
                if (!isFile(type)) {
                    BufferedSource source = responseBody.source();
                    source.request(Long.MAX_VALUE); // Buffer the entire body.
                    Buffer buffer = source.buffer();
                    //必须复制一个副本,否则原来的buffer被读取后导致内容清空
                    String text = buffer.clone().readString(charset);
                    Logger.d(TAG, text);
                } else {
                    Logger.d(TAG, "Binary stream byte[" + responseBody.contentLength() + "]");
                }
                logEnd("BODY");
            }


        }

        Logger.d(TAG, "<-- END HTTP");


        return response;
    }


    /**
     * 打印contentType和contentLength
     *
     * @param requestBody
     */
    private void logContentTypeAndLength(RequestBody requestBody) {
        try {
            if (requestBody != null) {
                MediaType contentType = requestBody.contentType();
                if (contentType != null) {
                    Logger.d(TAG, Content_Type + ":" + contentType);
                }
                long contentLength = requestBody.contentLength();
                if (contentLength != -1) {
                    Logger.d(TAG, Content_Length + ":" + contentLength + getFormatSize(contentLength));
                }
            }

        } catch (IOException e) {
        }

    }

    /**
     * 打印header
     *
     * @param headers
     */
    private void logHeaders(Headers headers, boolean printBoundary) {
        if (headers != null) {
            Set<String> names = headers.names();
            if (names.size() > 0) {
                Iterator<String> iterator = names.iterator();
                if (printBoundary) {
                    logStart("HEADER");
                }
                while (iterator.hasNext()) {
                    String name = iterator.next();
                    String value = headers.get(name);
                    Logger.d(TAG, name + ":" + value);
                }
                if (printBoundary) {
                    logEnd("HEADER");
                }
            }
        }
    }

    /**
     * 打印body数据
     *
     * @param requestBody
     */
    private void logBody(RequestBody requestBody) {
        try {
            if (requestBody != null) {
                Charset charset = null;
                MediaType contentType = requestBody.contentType();
                String type = "";
                if (contentType != null) {
                    charset = contentType.charset(UTF8);
                    type = contentType.toString();
                }
                if (charset == null) {
                    charset = UTF8;
                }
                if (!isFile(type)) {
                    Buffer buffer = new Buffer();
                    requestBody.writeTo(buffer);
                    String content = buffer.readString(charset);
                    Logger.d(TAG, content);
                } else {
                    Logger.d(TAG, "Binary stream byte[" + requestBody.contentLength() + "]");
                }

            }
        } catch (IOException e) {
        }

    }

    /**
     * 文件
     *
     * @param contentType
     * @return
     */
    private boolean isFile(String contentType) {
        if (contentType == null) return false;
        contentType = contentType.toLowerCase();
        return ContentType.OTCET_STREAM.equalsIgnoreCase(contentType)
                || ContentType.OCTET_STREAM.equalsIgnoreCase(contentType)
                || contentType.contains("image")
                || contentType.contains("video")
                || contentType.contains("audio")
                || contentType.contains("pdf")
                ;
    }



    /**
     * 把字节大小转化为 B K M
     *
     * @param size
     * @return
     */
    public static String getFormatSize(long size) {
        double kb = size / 1024f;
        if (kb < 1) {
            return "";
        }

        double mb = kb / 1024;
        if (mb < 1) {
            BigDecimal result1 = new BigDecimal(Double.toString(kb));
            return "(" + result1.setScale(2, BigDecimal.ROUND_HALF_UP)
                    .toPlainString() + "K" + ")";
        }

        double gb = mb / 1024;
        if (gb < 1) {
            BigDecimal result2 = new BigDecimal(Double.toString(mb));
            return "(" + result2.setScale(2, BigDecimal.ROUND_HALF_UP)
                    .toPlainString() + "M" + ")";
        }

        double tb = gb / 1024;
        if (tb < 1) {
            BigDecimal result3 = new BigDecimal(Double.toString(gb));
            return "(" + result3.setScale(2, BigDecimal.ROUND_HALF_UP)
                    .toPlainString() + "GB" + ")";
        }
        BigDecimal result4 = new BigDecimal(tb);
        return "(" + result4.setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString()
                + "TB" + ")";
    }

    private void logStart(@NonNull String tag) {
        Logger.d(TAG, "-- " + tag);
    }

    private void logEnd(@NonNull String tag) {
        Logger.d(TAG, "-- END " + tag);
    }

    public void setLevel(int level) {
        this.level = level;
    }


}
